package com.hivekion.files.controller;

import com.hivekion.common.Date.DateUtils;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.file.FileUtils;
import com.hivekion.files.domain.FileInfo;
import com.hivekion.files.domain.vo.MergeFileResult;
import com.hivekion.files.domain.vo.VerifyUploadResult;
import com.hivekion.files.mapper.FileInfoMapper;
import com.hivekion.files.service.IFileService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@RestController
@RequestMapping("/file")
public class FileController {

    @Autowired
    IFileService fileService;
    @Autowired
    FileInfoMapper fileInfoMapper; // 文件库，不需要可以去掉

    @Value("${uploadPath.projectfile}")
    private String uploadPath;

    @PostMapping("/verifyUpload")
    public VerifyUploadResult verifyUpload(String filename, String fileHash) {
        VerifyUploadResult result = new VerifyUploadResult();
        List<String> files = new ArrayList<>();
        FileInfo fileInfo = fileService.findFileByHash(fileHash);
        if (fileInfo != null) {
            result.setShouldUpload(true);
            result.setFilePath(fileInfo.getFilePath());
        } else {
            String filePath = uploadPath + "/" + filename;
            File _file = new File(filePath);
            if (_file.exists()) {
                //                try {
                //                    String hash = md5HashCode(filePath);
                //                    if (hash.equals(fileHash)) {
                //                        result.setShouldUpload(true);
                //                        result.setFilePath(filename);
                //                    }
                //                } catch (FileNotFoundException e) {
                //                    e.printStackTrace();
                //                }
                result.setShouldUpload(true);
                result.setFilePath(filename);
            } else {
                String file_name =
                        Arrays.stream(StringUtils.split(filename, ".")).findFirst().get();
                String fileDir = uploadPath + "/" + file_name;
                File dir = new File(fileDir);
                if (!dir.exists()) { // 目录不存在
                    result.setShouldUpload(false);
                    result.setUploadedList(files);
                } else {
                    File[] array = dir.listFiles(); // 获取目录下所有文件
                    for (int i = 0; i < array.length; i++) {
                        if (array[i].isFile()) {
                            files.add(array[i].getName());
                        }
                    }
                    result.setUploadedList(files);
                }
            }
        }
        return result;
    }

    @PostMapping("/chunkFile")
    @ApiParam(value = "切片上传")
    public String chunkFile(MultipartFile chunk, String hash, String filename, String fileHash) {
        String fileName = chunk.getOriginalFilename(); // 获取文件名
        String file_name = Arrays.stream(StringUtils.split(filename, ".")).findFirst().get();
        String fileDir = uploadPath + "/" + file_name;
        File dir = new File(fileDir);
        if (!dir.exists()) { // 目录不存在
            dir.mkdirs();
        }
        try {
            String newFileName = fileDir + "/" + StringUtils.split(hash, "-")[1];
            File newFile = new File(newFileName);
            chunk.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileName;
    }

    @PostMapping("/mergeFile")
    @ApiParam(value = "合并切片")
    public MergeFileResult mergeFile(String fileHash, String fileName) {
        MergeFileResult result = new MergeFileResult();
        String file_name = Arrays.stream(StringUtils.split(fileName, ".")).findFirst().get();
        String fileDir = uploadPath + "/" + file_name;
        File dir = new File(fileDir);
        if (!dir.exists()) { // 目录不存在
            throw new BusinessException(500, "未找到切片保存路径");
        }
        String newFileName = uploadPath + "/" + fileName; // 创建合并后的文件
        File file = new File(newFileName);
        if (file.exists()) {
            file.delete();
        }
        try {
            BufferedOutputStream destOutputStream =
                    new BufferedOutputStream(new FileOutputStream(newFileName));
            File[] array = dir.listFiles(); // 获取目录下所有文件
            for (int i = 0; i < array.length; i++) {
                File partFile = new File(fileDir, i + "");
                if (partFile.isFile()) {
                    // 循环将每个分片的数据写入目标文件
                    byte[] fileBuffer = new byte[1024]; // 文件读写缓存
                    int readBytesLength = 0; // 每次读取字节数
                    BufferedInputStream sourceInputStream =
                            new BufferedInputStream(new FileInputStream(partFile));
                    while ((readBytesLength = sourceInputStream.read(fileBuffer)) != -1) {
                        destOutputStream.write(fileBuffer, 0, readBytesLength);
                    }
                    sourceInputStream.close();
                }
            }
            destOutputStream.flush();
            destOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                String hash = md5HashCode(newFileName);
                if (!hash.equals(fileHash)) {
                    throw new BusinessException(500, "文件上传异常，hash值不一致");
                }
                System.out.println(hash);

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            result.setFileName(fileName);
            result.setFilePath(fileName);
            result.setFileHash(fileHash);
            return result;
        }
    }

    private String md5HashCode(String filePath) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream(filePath);
        return md5HashCode(fis);
    }

    private String md5HashCode(InputStream fis) {
        try {
            // 拿到一个MD5转换器,如果想使用SHA-1或SHA-256，则传入SHA-1,SHA-256
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 分多次将一个文件读入，对于大型文件而言，比较推荐这种方式，占用内存比较少。
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, length);
            }
            fis.close();
            // 转换并返回包含16个元素字节数组,返回数值范围为-128到127
            byte[] md5Bytes = md.digest();
            BigInteger bigInt = new BigInteger(1, md5Bytes); // 1代表绝对值
            return bigInt.toString(16); // 转换为16进制
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    @PostMapping("/uploadSignPhoto")
    @ApiParam(value = "上传签名图片")
    public String uploadSignPhoto(@RequestParam("file") MultipartFile file) {
        if (file.getSize() == 0 || file.isEmpty()) {
            throw new BusinessException(500, "签名不能为空");
        }
        String newFileName = "";
        String originalFilename = file.getOriginalFilename();
        String randomFileName = DateUtils.getRandomFileName();
        String fileName = randomFileName + "_" + originalFilename;
        String nowDay = DateUtils.getNowDay();
        String fileDir = File.separator + nowDay;
        File dir = new File(uploadPath + fileDir);
        if (!dir.exists()) { // 目录不存在
            dir.mkdirs();
        }
        try {
            newFileName = fileDir + File.separator + fileName;
            File newFile = new File(uploadPath + File.separator + newFileName);
            file.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return newFileName;
    }

    @ApiOperation("上传文件")
    @PostMapping("/UploadFile")
    public String UploadFile(MultipartFile chunk, String hash, String filename) {
        String fileName = chunk.getOriginalFilename(); // 获取文件名
        String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        String fileDir = uploadPath + "/" + DateUtils.getNowDay();
        File dir = new File(fileDir);
        if (!dir.exists()) { // 目录不存在
            dir.mkdirs();
        }
        fileName = DateUtils.getRandomFileName();
        String filPath = DateUtils.getNowDay() + "/" + fileName + suffix;
        try {
            String newFileName = fileDir + "/" + fileName + suffix;
            File newFile = new File(newFileName);
            chunk.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filPath;
    }

    @ApiOperation("导入手术文件")
    @PostMapping("/uploadOperationFile")
    @ApiImplicitParams({@ApiImplicitParam(name = "chunk", value = "文件", required = true),
            @ApiImplicitParam(name = "operationId", value = "手术id", required = true)})
    public String uploadOperationFile(MultipartFile chunk, String operationId) {
        String fileName = chunk.getOriginalFilename(); // 获取文件名
        String suffix = fileName.substring(fileName.lastIndexOf(".")); //后缀名
        String typePath = FileUtils.filePath(FileUtils.fileType(suffix));
        if (!StringUtils.isNoneBlank(typePath)) {
            throw new BusinessException(500, "不支持文件格式");
        }
        //CfArchOperation cfArchOperation = archOperationService.getById(operationId);
        //if (cfArchOperation == null) {
        //    throw new BusinessException(500, "未找到手术信息");
        //}
        String fileDir = uploadPath + "/operation/" + operationId + "/" + typePath;
        File dir = new File(fileDir);
        if (!dir.exists()) { // 目录不存在
            dir.mkdirs();
        }
        String randomFileName = DateUtils.getRandomFileName();
        String filPath = "";
        String resultPath = "";
        //String filPath = fileDir + "/"
        //        + (cfArchOperation.getPatientName() + "_" + randomFileName) + suffix;
        //String resultPath = "operation/" + operationId + "/" + typePath+ "/"
        //        + (cfArchOperation.getPatientName() + "_" + randomFileName) + suffix;
        try {
            File newFile = new File(filPath);
            chunk.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultPath;
    }
}
